package fdupc.crypto.aes;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * 类描述:  Aes加密解密处理工具
 *
 * @author 王雷
 * @version 1.0.0
 * @date 2023/1/31 0031 下午 4:28
 */
@Slf4j
public class AesUtil {

    /**
     * 功能描述：加密内容
     *
     * @param srcStr  加密原文
     * @param srcKey  加密密钥
     * @return 加密结果
     * @date: 2023/1/31 0031 下午 4:30
     */
    public static String encrypt(String srcStr, String srcKey) {
        return encrypt(srcStr, StandardCharsets.UTF_8, srcKey);
    }

    /**
     * 功能描述：加密内容
     *
     * @param srcStr  加密原文
     * @param charset 字符集，默认utf8
     * @param srcKey  加密密钥
     * @return 加密结果
     * @date: 2023/1/31 0031 下午 4:30
     */
    public static String encrypt(String srcStr, Charset charset, String srcKey) {
        if (parameterVerify(srcStr, srcKey)) {
            log.error("参数验证失败");
            return null;
        }

        charset = charset == null ? StandardCharsets.UTF_8 : charset;
        final SecretKeySpec sksAec = new SecretKeySpec(srcKey.getBytes(charset), "AES");

        try {
            final Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, sksAec);
            //使用Base64做转码，同时起到2次加密作用
            return new BASE64Encoder().encode(cipher.doFinal(srcStr.getBytes(charset)));
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
            log.error("srcStr：{}；charset：{}；srcKey：{}；加密处理逻辑异常", srcStr, charset, srcKey);
        }
        return null;
    }

    /**
     * 功能描述：参数验证
     *
     * @param srcStr 加密或解密原文
     * @param srcKey 密钥
     * @date: 2023/1/31 0031 下午 4:48
     */
    private static boolean parameterVerify(String srcStr, String srcKey) {
        if (StringUtils.isEmpty(srcStr) || StringUtils.isEmpty(srcKey)) {
            log.error("加密密文或加密密钥为空");
            return true;
        }
        if (srcKey.length() != 16) {
            log.error("加密密钥必须为16位");
            return true;
        }
        return false;
    }

    /**
     * 功能描述：解密
     *
     * @param srcStr  密文文
     * @param srcKey  密钥
     * @date: 2023/1/31 0031 下午 5:08
     */
    public static String decrypt(String srcStr, String srcKey) {
        return decrypt(srcStr, StandardCharsets.UTF_8, srcKey);
    }

    /**
     * 功能描述：解密
     *
     * @param srcStr  密文文
     * @param charset 字符集，默认utf8
     * @param srcKey  密钥
     * @date: 2023/1/31 0031 下午 5:08
     */
    public static String decrypt(String srcStr, Charset charset, String srcKey) {
        if (parameterVerify(srcStr, srcKey)) {
            log.error("参数验证失败");
            return null;
        }
        charset = charset == null ? StandardCharsets.UTF_8 : charset;
        final SecretKeySpec sksAec = new SecretKeySpec(srcKey.getBytes(charset), "AES");

        try {
            final Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, sksAec);
            //先用Base64解密
            final byte[] doFinal = cipher.doFinal(new BASE64Decoder().decodeBuffer(srcStr));
            return new String(doFinal, charset);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException | IOException e) {
            log.error("解密处理失败", e);
            return null;
        }
    }

    public static void main(String[] values){
        String scrKey = "jkl;POIU1234++==";
        final String encrypt = encrypt("Test测试——kdidiso-;safasdfas", StandardCharsets.UTF_8, scrKey);
        log.error("加密结果：{}", encrypt);
        final String decrypt = decrypt(encrypt, StandardCharsets.UTF_8, scrKey);
        log.error("解密结果：{}", decrypt);
    }
}
